/*  J
**  Date 2007-05-30 23:35:06 
**  File tag.c  v 1.0
**  Author Mucker
**  See Copyright Notice in J.h
**  
*/

#include "J.h"

#include "tag.h"
#include "lex.h"
#include "object.h"
#include "mem.h"

static void rehash(tag_table *ttag, size_t nsize)
{

	Jobject **obj;
	size_t i;

    obj = Mnvector(nsize, Jobject);

	for(i = 0; i < nsize; i++) obj[i] = NULL;
	
	for(i = 0; i <ttag->size; i++){

		Jobject *tp = ttag->obj[i];

		while(tp){
			Jobject *next = tp->next;

			unsigned int hh = Mobj2str(tp)->h;

			unsigned int index = Mmod(hh, nsize);

			tp->next = obj[index];
			obj[index] = tp;

			tp = next;
		}
	}

	mem_free(ttag->obj);
	ttag->obj = obj;
	ttag->size = nsize;

}

static Jstring* new_tag(lex_state *ls, const char *str, size_t len, unsigned int index)
{
	Jstring *Jstr;
	tag_table *ttag;

	Jstr = Mmalloc(sizeof(Jstring) + len+1);

	Jstr->h = index;
	Jstr->keyword = 0;
	Jstr->len = len;
	Jstr->next = NULL;
	Jstr->type = J_STRING;

	memcpy(Jstr+1, str, len);
	((char*)(Jstr+1))[len] = '\0';

	ttag = ls->ttag;

	index = Mmod(index, ttag->size);

	Jstr->next = ttag->obj[index];

	ttag->obj[index] = cast(Jobject *, Jstr);
	ttag->count ++;
	if(ttag->count >= ttag->size )
		rehash(ttag, ttag->size * 2);
	return Jstr;
}


Jstring * tag_new(lex_state *ls, const char *str, size_t len)
{
    unsigned int  h = cast(unsigned int , len);
	
	Jobject *obj;

    size_t step = (len >> 5) +1 ; 
    size_t len1 ;

    for(len1=len ; len1>=step; len1-=step){
        h = h^( (h<<5) + (h>>2) + cast(unsigned char , str[len1-1]));
    }
	for(obj =  ls->ttag->obj[Mmod(h, ls->ttag->size)];
		obj != NULL;
		obj = obj->next){

			Jstring *Jstr = Mobj2str(obj);	
			if((Jstr->len == len) & (memcmp(str, Mgetstr(Jstr), len) == 0))
				return Jstr;
	}

	return new_tag(ls, str, len, h);
}

tag_table * tag_init(tag_table *ttag)
{
	ttag = Mmalloc(sizeof(tag_table));  
	ttag->size = 0;
	ttag->count = 0;
	ttag->obj = NULL;
	rehash(ttag, 4);
	return ttag;
}